﻿using Prime31;
using System.Threading;
using UnityEngine;
/// <summary>
/// 角色移动控制,上下左右,跑跳之类的
/// </summary>
[RequireComponent(typeof(CharacterController2D))]
[RequireComponent(typeof(BoxCollider2D))]
[RequireComponent(typeof(Rigidbody2D))]
public class playerControl : MonoBehaviour
{
    // movement config
    public float gravity = -25f;
    public float groundDamping = 20f; // how fast do we change direction? higher means faster
    public float inAirDamping = 5f;
    public float jumpHeight = 3f;
    //移动控制按钮
    public KeyCode left;
    public KeyCode right;
    public KeyCode down;
    public KeyCode up;
    public KeyCode jump;
    public state state;

    [HideInInspector]
    private float normalizedHorizontalSpeed = 0;
    [HideInInspector]
    public float normalizedVerticalSpeed;
    //传送门
    [HideInInspector]
    public bool isInTransDoor = false;
    public CharacterController2D _controller;
    public Animator animator;
    private RaycastHit2D _lastControllerColliderHit;
    public Vector3 _velocity;
    private void OnCollisionEnter2D(Collision2D collision)
    {
        Debug.Log(" gameObject:" + collision.gameObject.name);

    }
    void Awake()
    {
        // _animator = GetComponent<Animator>();
        _controller = GetComponent<CharacterController2D>();

        // listen to some events for illustration purposes
        _controller.onControllerCollidedEvent += onControllerCollider;
        _controller.onTriggerEnterEvent += onTriggerEnterEvent;
        _controller.onTriggerExitEvent += onTriggerExitEvent;
    }




    void onControllerCollider(RaycastHit2D hit)
    {
        // bail out on plain old ground hits cause they arent very interesting
        if (hit.normal.y == 1f)
            return;

        // logs any collider hits if uncommented. it gets noisy so it is commented out for the demo
        //Debug.Log( "flags: " + _controller.collisionState + ", hit.normal: " + hit.normal );
    }
    /// <summary>
    /// 玩家受击函数
    /// </summary>
    /// <param name="source">技能释放者</param>
    /// <param name="damage">技能基本伤害</param>
    /// <param name="interruptable">受击过程</param>
    public void hit(GameObject source, float damage, bool interruptable)
    {

    }
    /// <summary>
    /// 玩家受击函数
    /// </summary>
    /// <param name="source">技能释放者</param>
    /// <param name="damage">技能基本伤害</param>
    public void hit(GameObject source, float damage)
    {
        //玩家减血
        state.health += damage;
        //受击玩家播放受击音效
        GetComponent<AudioSource>().Play();
        //如果当前不是硬直状态,就播放受击动画
        if (!state.isStiff)
        {
            //播放受击动画
            animator.SetBool("isHurting", true);
        }
        state.movementState = state.MovementState.HURTING;
        //受击过程不能动
        state.isMovable = false;
        //打断当前可被打断的技能执行
        GetComponent<skillControl>().interruptCurrentSkill();
        //延迟一段时间,期间无法移动
        new Thread((a) =>
        {
            //受击过程至少持续200ms，如果200ms后受击者还在空中，就直到他落地才可以控制
            //这里会出现问题，在弹簧上面是无法落地的，会一直弹，因为弹簧的层不是地面，
            //这里使用一个最大超时时间，也可以保证任何技能不能一直把受击角色一直悬空
            Thread.Sleep(500);
            int tmpTime = 0;
            while (!_controller.isGrounded && tmpTime < 100)
            {
                Thread.Sleep(5);
                tmpTime++;
            }
            Loom.QueueOnMainThread((a) =>
            {
                state.isMovable = true;
                animator.SetBool("isHurting", false);
                state.movementState = state.MovementState.IDLE;

            }, null);

        }).Start();


    }
    void onTriggerEnterEvent(Collider2D col)
    {
        Debug.Log("onTriggerEnterEvent: " + col.gameObject.name);
    }


    void onTriggerExitEvent(Collider2D col)
    {
        Debug.Log("onTriggerExitEvent: " + col.gameObject.name);

    }

    void Start()
    {

    }
    /// <summary>
    /// 增加一个buff到角色身上
    /// </summary>
    /// <param name="buff"></param>
    public void addBuff(GameObject buff)
    {

        Vector3 pos = this.transform.position;
        pos.z = -1;

        //在同一时刻，只能存在一个同一类型的buff，如果已经存在此buff则忽略
        if (!transform.Find(buff.name + "(Clone)"))
        {
            Instantiate(buff, pos, this.transform.rotation, this.transform);

        }

    }
    /// <summary>
    /// 跳跃
    /// </summary>
    /// <param name="jumpHeight">跳跃高度</param>
    public void Jump(float jumpHeight)
    {
        if (state.currentJumpCnt <= 0) { return; }
        _velocity.y = Mathf.Sqrt(2f * jumpHeight * -gravity);
        state.movementState = state.MovementState.FLOATING;
        state.currentJumpCnt--;

    }
    /// <summary>
    /// 在任意方向上给角色一个速度
    /// </summary>
    /// <param name="vector">速度</param>
    public void move(Vector3 vector)
    {
        _velocity += vector;
    }
    // the Update loop contains a very simple example of moving the character around and controlling the animation
    void Update()
    {
        //if (_controller.isGrounded)
        //    _velocity.y = 0;
        if (Input.GetKey(right) && state.isMovable && (state.movementState == state.MovementState.RUNNING || state.movementState == state.MovementState.IDLE || state.movementState == state.MovementState.FLOATING))
        {
            animator.SetBool("isWalking", true);
            normalizedHorizontalSpeed = 1;
            // if (state.movementState != state.MovementState.FLOATING)
            // {
            //     state.movementState = state.MovementState.RUNNING;

            // }
            if (transform.localScale.x < 0f)
                transform.localScale = new Vector3(-transform.localScale.x, transform.localScale.y, transform.localScale.z);

            // if( _controller.isGrounded )
            // _animator.Play( Animator.StringToHash( "Run" ) );
        }
        else if (Input.GetKey(left) && state.isMovable && (state.movementState == state.MovementState.RUNNING || state.movementState == state.MovementState.IDLE || state.movementState == state.MovementState.FLOATING))
        {
            animator.SetBool("isWalking", true);

            normalizedHorizontalSpeed = -1;
            // if (state.movementState != state.MovementState.FLOATING)
            // {
            //     state.movementState = state.MovementState.RUNNING;

            // }

            if (transform.localScale.x > 0f)
                transform.localScale = new Vector3(-transform.localScale.x, transform.localScale.y, transform.localScale.z);

            // if( _controller.isGrounded )
            // _animator.Play( Animator.StringToHash( "Run" ) );
        }
        else
        {
            animator.SetBool("isWalking", false);
            normalizedHorizontalSpeed = 0;
            // if (state.movementState == state.MovementState.RUNNING)
            // {
            //     state.movementState = state.MovementState.IDLE;

            // }

            // if( _controller.isGrounded )
            // _animator.Play( Animator.StringToHash( "Idle" ) );
        }


        // 只能不爬楼梯的时候跳
        //todo:这里有一个bug,人物在楼梯下的时候无法跳跃,
        //暂时先不管
        if (Input.GetKeyDown(jump) && !state.isOnLadder)
        {
            // Debug.Log("jumpcnt:" + jumpCnt);
            if (state.isMovable && state.movementState != state.MovementState.CLIMBING)
            {
                Debug.Log("jump from pc");
                Jump(jumpHeight);

            }


        }

        // apply horizontal speed smoothing it. dont really do this with Lerp. Use SmoothDamp or something that provides more control
        var smoothedMovementFactor = _controller.isGrounded ? groundDamping : inAirDamping; // how fast do we change direction?
        //如果角色当前正在攀爬梯子，就没有x轴方向的速度，而有y轴方向的速度
        if (state.movementState == state.MovementState.CLIMBING)
        {
            _velocity.x = 0;
            _velocity.y = Mathf.Lerp(_velocity.y, normalizedVerticalSpeed * state.runSpeed / 2.0f, Time.deltaTime * smoothedMovementFactor);
        }
        else
        {
            _velocity.x = Mathf.Lerp(_velocity.x, normalizedHorizontalSpeed * state.runSpeed, Time.deltaTime * smoothedMovementFactor);
        }


        //如果正在爬楼梯,就取消重力,防止掉下来
        if (state.movementState != state.MovementState.CLIMBING)
        {
            // apply gravity before moving
            _velocity.y += gravity * Time.deltaTime;

        }

        // if holding down bump up our movement amount and turn off one way platform detection for a frame.
        // this lets us jump down through one way platforms
        //if (_controller.isGrounded && Input.GetKey(down))
        //{
        //    _controller.ignoreOneWayPlatformsThisFrame = true;
        //    _velocity.y *= 3f;

        //}
        _controller.move(_velocity * Time.deltaTime);

        // grab our current _velocity to use as a base for all calculations
        _velocity = _controller.velocity;

        //如果角色刚从浮空状态下落地,就转换为空闲状态
        //如果在浮空的时候释放技能,状态会变成释放技能,
        //所以在这个状态下也应该能够重置跳跃
        //暂时就先这样处理吧
        if (_controller.isGrounded && (state.movementState == state.MovementState.FLOATING || state.movementState == state.MovementState.IDLE))
        {
            Debug.Log("is grounded");
            state.movementState = state.MovementState.IDLE;
            state.canClimb = true;
            state.resetMultiJumpCnt();
        }

    }

}
